package com.thoughtworks.refactor;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Poker {
    public String compairResult(String blackHands, String whiteHands) {
        String winResult = "";
        String blackType = getHandsCategory(blackHands);
        String whiteType = getHandsCategory(whiteHands);
        String[] handsCategories = {"StraightFlush", "FourOfAKind", "FullHouse", "Flush", "Straight", "ThreeOfAKind", "TwoPair", "OnePair", "HighCard"};
        int[] blackHandsNumbers = getDescendingHandsNumbers(blackHands);
        int[] whiteHandsNumbers = getDescendingHandsNumbers(whiteHands);
        int blackHandsCategoryRank = getHandsCategoryRank(blackType);
        int whiteHandsCategoryRank = getHandsCategoryRank(whiteType);
        int[] descendingBlackHandsNumbers = descendingSort(blackHandsNumbers );
        int[] descendingWhiteHandsNumbers = descendingSort(whiteHandsNumbers );
        int[] repeatBlackHandsNumbers = getRepeatNumbers(blackHandsNumbers);
        int[] repeatWhiteHandsNumbers = getRepeatNumbers(whiteHandsNumbers);
        int[] noRepeatBlackHandsNumbers = getNoRepeatNumbers(blackHandsNumbers);
        int[] noRepeatWhiteHandsNumbers = getNoRepeatNumbers(whiteHandsNumbers);
        if (blackHandsCategoryRank  < whiteHandsCategoryRank ) {
            winResult = "black wins - " + handsCategories [blackHandsCategoryRank ];
        } else if (blackHandsCategoryRank  > whiteHandsCategoryRank ) {
            winResult = "white wins - " + handsCategories [whiteHandsCategoryRank ];
        } else {
            if (blackHandsCategoryRank  == 0) { //同花顺
                if (blackHandsNumbers [0] < whiteHandsNumbers [0]) {
                    String sig = intNumber(whiteHandsNumbers [0]);
                    winResult = "white wins - high card:" + sig;
                } else if (blackHandsNumbers [0] > whiteHandsNumbers [0]) {
                    String sig = intNumber(blackHandsNumbers [0]);
                    winResult = "black wins - high card:" + sig;
                } else {
                    winResult = "tie";
                }
            } else if (blackHandsCategoryRank  == 1) { //铁支
                if (descendingBlackHandsNumbers [0] < descendingWhiteHandsNumbers [0]) {
                    String sig = intNumber(descendingWhiteHandsNumbers [0]);
                    winResult = "white wins - high card:" + sig;
                } else {
                    String sig = intNumber(descendingBlackHandsNumbers [0]);
                    winResult = "black wins - high card:" + sig;
                }
            } else if (blackHandsCategoryRank  == 2) { //葫芦
                if (descendingBlackHandsNumbers [0] < descendingWhiteHandsNumbers [0]) {
                    String sig = intNumber(descendingWhiteHandsNumbers [0]);
                    winResult = "white wins - high card:" + sig;
                } else {
                    String sig = intNumber(descendingBlackHandsNumbers [0]);
                    winResult = "black wins - high card:" + sig;
                }
            } else if (blackHandsCategoryRank  == 3) { //同花
                for (int i = 0; i < 5; i++) {
                    if (blackHandsNumbers [i] < whiteHandsNumbers [i]) {
                        String sig = intNumber(whiteHandsNumbers [i]);
                        winResult = "white wins - high card:" + sig;
                        break;
                    } else if (blackHandsNumbers [i] > whiteHandsNumbers [i]) {
                        String sig = intNumber(blackHandsNumbers [i]);
                        winResult = "black wins - high card:" + sig;
                        break;
                    } else {
                        winResult = "tie";
                    }
                }
            } else if (blackHandsCategoryRank  == 4) { //顺子
                if (blackHandsNumbers [0] < whiteHandsNumbers [0]) {
                    String sig = intNumber(whiteHandsNumbers [0]);
                    winResult = "white wins - high card:" + sig;
                } else if (blackHandsNumbers [0] > whiteHandsNumbers [0]) {
                    String sig = intNumber(blackHandsNumbers [0]);
                    winResult = "black wins - high card:" + sig;
                } else {
                    winResult = "tie";
                }
            } else if (blackHandsCategoryRank  == 5) { //三条
                if (repeatBlackHandsNumbers[0] < repeatWhiteHandsNumbers[0]) {
                    String sig = intNumber(repeatWhiteHandsNumbers[0]);
                    winResult = "white wins - high card:" + sig;
                } else {
                    String sig = intNumber(repeatBlackHandsNumbers[0]);
                    winResult = "black wins - high card:" + sig;
                }
            } else if (blackHandsCategoryRank  == 6) { //两对
                for (int i = 0; i < 2; i++) {
                    if (repeatBlackHandsNumbers[i] < repeatWhiteHandsNumbers[i]) {
                        String sig = intNumber(repeatWhiteHandsNumbers[i]);
                        winResult = "white wins - high card:" + sig;
                        break;
                    } else if (repeatBlackHandsNumbers[i] > repeatWhiteHandsNumbers[i]) {
                        String sig = intNumber(repeatBlackHandsNumbers[i]);
                        winResult = "black wins - high card:" + sig;
                        break;
                    }
                }
                if (winResult == "") {
                    if (noRepeatBlackHandsNumbers[0] < noRepeatWhiteHandsNumbers[0]) {
                        String sig = intNumber(noRepeatWhiteHandsNumbers[0]);
                        winResult = "white wins - high card:" + sig;
                    } else if (noRepeatBlackHandsNumbers[0] > noRepeatWhiteHandsNumbers[0]) {
                        String sig = intNumber(noRepeatBlackHandsNumbers[0]);
                        winResult = "black wins - high card:" + sig;
                    } else {
                        winResult = "tie";
                    }
                }
            } else if (blackHandsCategoryRank  == 7) { //对子
                if (repeatBlackHandsNumbers[0] < repeatWhiteHandsNumbers[0]) {
                    String sig = intNumber(repeatWhiteHandsNumbers[0]);
                    winResult = "white wins - high card:" + sig;
                } else if (repeatBlackHandsNumbers[0] > repeatWhiteHandsNumbers[0]) {
                    String sig = intNumber(repeatBlackHandsNumbers[0]);
                    winResult = "black wins - high card:" + sig;
                } else {
                    for (int i = 0; i < 3; i++) {
                        if (noRepeatBlackHandsNumbers[i] < noRepeatWhiteHandsNumbers[i]) {
                            String sig = intNumber(noRepeatWhiteHandsNumbers[i]);
                            winResult = "white wins - high card:" + sig;
                            break;
                        } else if (noRepeatBlackHandsNumbers[i] > noRepeatWhiteHandsNumbers[i]) {
                            String sig = intNumber(noRepeatBlackHandsNumbers[i]);
                            winResult = "black wins - high card:" + sig;
                            break;
                        } else {
                            winResult = "tie";
                        }
                    }
                }
            } else { //散牌
                for (int i = 0; i < 5; i++) {
                    if (blackHandsNumbers [i] < whiteHandsNumbers [i]) {
                        String sig = intNumber(whiteHandsNumbers [i]);
                        winResult = "white wins - high card:" + sig;
                        break;
                    } else if (blackHandsNumbers [i] > whiteHandsNumbers [i]) {
                        String sig = intNumber(blackHandsNumbers [i]);
                        winResult = "black wins - high card:" + sig;
                        break;
                    } else {
                        winResult = "tie";
                    }
                }
            }
        }
        return winResult;
    }

    private String intNumber(int i) {
        String[] strNumber = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"};
        return strNumber[i - 2];
    }

    private int[] descendingSort(int[] handsNumbers) {
        return IntStream.of(handsNumbers)
                .boxed()
                .sorted(Comparator.reverseOrder())
                .mapToInt(i -> i)
                .toArray();
    }

    private int[] getNoRepeatNumbers(int[] handsNumbers) {
        return IntStream.of(handsNumbers)
                .filter(number -> Collections.frequency(Arrays.stream(handsNumbers).boxed().collect(Collectors.toList()), number) == 1)
                .toArray();
    }

    private int[] getRepeatNumbers(int[] handsNumbers) {
        return IntStream.of(handsNumbers)
                .filter(number -> Collections.frequency(Arrays.stream(handsNumbers)
                        .boxed()
                        .collect(Collectors.toList()), number) > 1)
                .distinct()
                .toArray();
    }

    private int getHandsCategoryRank(String handsCategory) {
        int index = -1;
        String[] handsCategories = {"StraightFlush", "FourOfAKind", "FullHouse", "Flush", "Straight", "ThreeOfAKind", "TwoPair", "OnePair", "HighCard"};
        for (int i = 0; i < 9; i++) {
            if (handsCategories[i].equals(handsCategory)) {
                index = i;
            }
        }
        return index;
    }

    private String getHandsCategory(String hands) {
        if (isStraightFlush(hands)) {
            return "StraightFlush";
        }
        if (isStraight(hands)) {
            return "Straight";
        }
        if (isFlush(hands)) {
            return "Flush";
        }
        if (isHighCard(hands)) {
            return "HighCard";
        }
        if (isOnePair(hands)) {
            return "OnePair";
        }
        if (isTwoPair(hands)) {
            return "TwoPair";
        }
        if (isThreeOfAKind(hands)) {
            return "ThreeOfAKind";
        }
        if (isFourOfAKind(hands)) {
            return "FourOfAKind";
        }
        return "FullHouse";
    }

    private boolean isFourOfAKind(String hands) {
        int[] handsNumbers = getDescendingHandsNumbers(hands);
        return handsNumbers[0] != handsNumbers[1] || handsNumbers[3] != handsNumbers[4];
    }

    private boolean isThreeOfAKind(String hands) {
        return countDistinctNumbers(hands) == 3;
    }

    private boolean isTwoPair(String hands) {
        int[] handsNumbers = getDescendingHandsNumbers(hands);
        return countDistinctNumbers(hands) == 3 &&
                ((handsNumbers[0] == handsNumbers[1] && handsNumbers[2] == handsNumbers[3]) ||
                        (handsNumbers[1] == handsNumbers[2] && handsNumbers[3] == handsNumbers[4]) ||
                        (handsNumbers[0] == handsNumbers[1] && handsNumbers[3] == handsNumbers[4]));
    }

    private boolean isOnePair(String hands) {
        return countDistinctNumbers(hands) == 4;
    }

    private boolean isHighCard(String hands) {
        return countDistinctNumbers(hands) == 5;
    }

    private boolean isFlush(String hands) {
        return countDistinctNumbers(hands) == 5 && countSuits(hands) == 1;
    }

    private boolean isStraight(String hands) {
        int[] handsNumbers = getDescendingHandsNumbers(hands);
        return countDistinctNumbers(hands) == 5 && handsNumbers[0] - handsNumbers[4] == 4;
    }

    private boolean isStraightFlush(String hands) {
        int[] handsNumbers = getDescendingHandsNumbers(hands);
        return countDistinctNumbers(hands) == 5 && handsNumbers[0] - handsNumbers[4] == 4 && countSuits(hands) == 1;
    }

    private int countDistinctNumbers(String hands) {
        int i;
        HashSet<Integer> distinctNumbers = new HashSet<Integer>();
        for (i = 0; i < 5; i++) {
            distinctNumbers.add(getDescendingHandsNumbers(hands)[i]);
        }
        int distinctNumbersCount = distinctNumbers.size();
        return distinctNumbersCount;
    }

    private int countSuits(String hands) {
        String[] strArray = hands.split("");
        int i;
        String[] suit = new String[5];
        for (i = 0; i < 5; i++) {
            suit[i] = strArray[i * 3 + 1];
        }
        HashSet<String> suits = new HashSet<String>();
        for (i = 0; i < 5; i++) {
            suits.add(suit[i]);
        }
        int suitsCount = suits.size();
        return suitsCount;
    }

    //数字转化并将其从大到小排序
    private int[] getDescendingHandsNumbers(String str) {
        int[] number = new int[5];
        String[] strArray = str.split("");
        int i;
        for (i = 0; i < 5; i++) {
            String c = strArray[i * 3];
            switch (c) {
                case "T":
                    number[i] = 10;
                    break;
                case "J":
                    number[i] = 11;
                    break;
                case "Q":
                    number[i] = 12;
                    break;
                case "K":
                    number[i] = 13;
                    break;
                case "A":
                    number[i] = 14;
                    break;
                default:
                    number[i] = Integer.valueOf(c);
                    break;
            }
        }

        Arrays.sort(number);
        int[] renumber = new int[number.length];
        for (i = 0; i < number.length; i++) {
            renumber[i] = number[number.length - i - 1];
        }
        return renumber;
    }
}
